package com.ease.model.criterion;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.ease.common.util.Detect;
import com.ease.common.vo.Entry;

/**
 * 
 * @author nathanleewei
 * 
 */
public class QueryCriteria extends Detect implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = 1190733863214493149L;

	// public static final String QUERY_CRITERIA_ALIAS="T";

	// protected JdbcTemplateDialect dialet;

	protected List<Criterion> criteria;

	private static final int MAX_SIZE = 1000;

	public String getColumnNameByPropertyName(String propertyName, Object value) {
		return propertyName;
	}

	public String getSpecialCondition(String propertyName) {
		return "";
	}

	public void add(Criterion criterion) {
		if (null == criterion)
			return;
		this.getCriteria().add(criterion);
	}

	public void add(QueryCriteria queryCriteria) {
		if (null != queryCriteria && notEmpty(queryCriteria.getCriteria())) {
			this.getCriteria().addAll(queryCriteria.getCriteria());
		}
	}

	protected String toSqlString() {
		if (!notEmpty(criteria))
			return "1=1";

		Iterator<Criterion> iterator = criteria.iterator();

		StringBuffer buffer = new StringBuffer();
		while (iterator.hasNext()) {
			buffer.append(iterator.next().toSqlString(this));
			if (iterator.hasNext())
				buffer.append(' ').append(" and ");
		}
		return buffer.toString();
	}

	@SuppressWarnings("deprecation")
	protected List<Entry<String, Object>> getNamedValue() {
		List<Entry<String, Object>> namedValue = new ArrayList<Entry<String, Object>>();
		Iterator<Criterion> iterator = criteria.iterator();
		while (iterator.hasNext()) {
			namedValue.addAll(iterator.next().getNamedValue(this));
		}
		return namedValue;
	}

	public NamedCriteraParamater toNamedCriteraParameter() {
		NamedCriteraParamater namedCriteraParameter = new NamedCriteraParamater();

		String namedSqlString = this.toSqlString();
		Map<String, Object> namedParameter = new HashMap<String, Object>();
		if (notEmpty(criteria)) {
			List<Entry<String, Object>> namedValues = this.getNamedValue();

			for (int i = 0; i < namedValues.size(); i++) {
				Entry<String, Object> namedValue = namedValues.get(i);
				String propertyName = namedValue.getKey();
				Object value = namedValue.getValue();

				if (namedParameter.containsKey(propertyName)) {
					propertyName = this.generateUniquePropertyName(propertyName, namedParameter);
				}
				namedParameter.put(propertyName, toSpecialValue(propertyName, value));
				namedSqlString = StringUtils.replace(namedSqlString, "?", toSpecialParameterName(propertyName), 1);
			}
		}

		namedCriteraParameter.setNamedParameter(namedParameter);
		namedCriteraParameter.setNamedSqlString(namedSqlString);
		return namedCriteraParameter;
	}

	public String toSpecialParameterName(String propertyName) {
		return ":" + propertyName;
	}

	public Object toSpecialValue(String propertyName, Object value) {
		return value;
	}

	// public JdbcTemplateDialect getDialet() {
	// return dialet;
	// }
	//
	// public void setDialet(JdbcTemplateDialect dialet) {
	// this.dialet = dialet;
	// }

	public void addMapParameter(Map<String, Object> parameter) {
		if (notEmpty(parameter)) {
			Iterator<String> iterator = parameter.keySet().iterator();
			while (iterator.hasNext()) {
				String propertyName = iterator.next();
				Object value = parameter.get(propertyName);
				if (null != value) {
					this.add(Restrictions.eq(propertyName, value));
				}
			}
		}
	}

	protected String generateUniquePropertyName(String propertyName, Map<String, Object> parameters) {
		if (null == parameters || !parameters.containsKey(propertyName))
			return propertyName;

		// we assume that a unique propertyname will be found at last
		for (int i = 1; i < MAX_SIZE; i++) {
			String finalPropertyName = propertyName + "_" + i;
			if (!parameters.containsKey(finalPropertyName))
				return finalPropertyName;
		}

		return propertyName;

	}

	public List<Criterion> getCriteria() {
		if (null == criteria) {
			criteria = new ArrayList<Criterion>();
		}
		return criteria;
	}

	public void setCriteria(List<Criterion> criteria) {
		this.criteria = criteria;
	}

	public class NamedCriteraParamater {
		private String namedSqlString;
		private Map<String, Object> namedParameter;

		public String getNamedSqlString() {
			return namedSqlString;
		}

		public void setNamedSqlString(String namedSqlString) {
			this.namedSqlString = namedSqlString;
		}

		public Map<String, Object> getNamedParameter() {
			return namedParameter;
		}

		public void setNamedParameter(Map<String, Object> namedParameter) {
			this.namedParameter = namedParameter;
		}

	}

}
